package com.ruoyi.system.config;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitMQConfig {

    // 队列名称
    public static final String CACHE_SYNC_DB_QUEUE = "cache_sync_db_queue";
    // 交换机名称
    public static final String CACHE_SYNC_DB_EXCHANGE = "cache_sync_db_exchange";
    // 路由键
    public static final String CACHE_ROUTING_DB_KEY = "cache_routing_db_key";

    /**
     * 定义队列
     * durable: 是否持久化（队列在服务器重启后是否存在）
     * exclusive: 是否排他（仅当前连接可见，连接关闭后删除）
     * autoDelete: 是否自动删除（当最后一个消费者断开连接后删除）
     */
    @Bean
    public Queue testQueue() {
        return new Queue(CACHE_SYNC_DB_QUEUE, true, false, false);
    }

    /**
     * 定义直连交换机（DirectExchange）
     * 特点：消息根据路由键完全匹配才能被路由到对应的队列
     */
    @Bean
    public DirectExchange testExchange() {
        return new DirectExchange(CACHE_SYNC_DB_EXCHANGE, true, false);
    }

    /**
     * 绑定队列到交换机，并指定路由键
     */
    @Bean
    public Binding bindingTestQueue(Queue testQueue, DirectExchange testExchange) {
        return BindingBuilder
                .bind(testQueue)
                .to(testExchange)
                .with(CACHE_ROUTING_DB_KEY);
    }

    // 配置JSON消息转换器
    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }

    /**
     * 生产者确认消息   配置RabbitTemplate，设置确认回调
     * @param connectionFactory
     * @return
     */
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMessageConverter(messageConverter());

        // 设置确认回调：生产者确认消息是否到达交换机
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if (correlationData != null) {
                String messageId = correlationData.getId();
                if (ack) {
                    System.out.println("消息[" + messageId + "]已成功到达交换机");
                } else {
                    System.err.println("消息[" + messageId + "]未到达交换机，原因：" + cause);
                }
            }
        });

        // 设置返回回调：生产者处理无法路由到队列的消息
        rabbitTemplate.setReturnsCallback(returnedMessage -> {
            System.err.println("消息无法路由到队列：" +
                    "消息ID=" + returnedMessage.getMessage().getMessageProperties().getMessageId() +
                    ", 交换机=" + returnedMessage.getExchange() +
                    ", 路由键=" + returnedMessage.getRoutingKey() +
                    ", 原因=" + returnedMessage.getReplyText());
        });

        // 确保消息在无法路由时会被返回给生产者
        rabbitTemplate.setMandatory(true);

        return rabbitTemplate;
    }

}
